' 
' Copyright (C) 2014 Infinity CCS Ltd (http://www.infinityccs.com/)
' Copyright (C) 2008 Sasa Coh <sasacoh@gmail.com>
'
' This program is free software; you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation; either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
' GNU General Public License for more details.
'
' You should have received a copy of the GNU General Public License
' along with this program.  If not, see <http://www.gnu.org/licenses/>. 
'/

Imports System.Runtime.InteropServices
Imports System
Imports System.Text
Imports Infinity.pjsipNET.Common

''' <summary>
''' Implementation of SIP interface using pjsip.org SIP stack.
''' This proxy is used for sip stack initialization and shut down, registration, and 
''' callback methods handling.
''' </summary>
Public Class pjsipStackProxy
  Inherits IVoipProxy
#Region "Constructor"

  Private Shared _instance As pjsipStackProxy = Nothing

  Public Shared ReadOnly Property Instance As pjsipStackProxy
    Get
      If _instance Is Nothing Then _instance = New pjsipStackProxy
      Return _instance
    End Get
  End Property

  Protected Sub New()

  End Sub
#End Region

#Region "Properties"

  Private _initialized As Boolean = False
  Public Overrides Property IsInitialized As Boolean
    Get
      Return _initialized
    End Get
    Set(value As Boolean)
      _initialized = value
    End Set
  End Property
#End Region

#Region "Wrapper functions"
  <DllImport("Infinity.pjsip.dll", EntryPoint:="dll_init", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function dll_init() As Integer

  End Function
  <DllImport("Infinity.pjsip.dll", EntryPoint:="dll_main", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function dll_main() As Integer

  End Function
  <DllImport("Infinity.pjsip.dll", EntryPoint:="dll_shutdown", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function dll_shutdown() As Integer

  End Function
  <DllImport("Infinity.pjsip.dll", EntryPoint:="dll_setSipConfig", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Sub dll_setSipConfig(config As pjsipConfig)

  End Sub


  <DllImport("Infinity.pjsip.dll", EntryPoint:="dll_getCodec", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function dll_getCodec(index As Integer, codec As StringBuilder) As Integer

  End Function
  <DllImport("Infinity.pjsip.dll", EntryPoint:="dll_getNumOfCodecs", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function dll_getNumOfCodecs() As Integer

  End Function
  <DllImport("Infinity.pjsip.dll", EntryPoint:="dll_setCodecPriority", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function dll_setCodecPriority(name As String, prio As Integer) As Integer

  End Function
  <DllImport("Infinity.pjsip.dll", EntryPoint:="dll_setSoundDevice", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function dll_setSoundDevice(playbackDeviceId As String, recordingDeviceId As String) As Integer

  End Function

#End Region 'Wrapper functions

#Region "Callback declarations"

  <DllImport("Infinity.pjsip.dll", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function setCallback_onDtmfDigit(cb As delOnDtmfDigitCallback) As Integer

  End Function
  <DllImport("Infinity.pjsip.dll", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function setCallback_onMessageWaiting(cb As delOnMessageWaitingCallback) As Integer

  End Function
  <DllImport("Infinity.pjsip.dll", CallingConvention:=CallingConvention.Cdecl)>
  Private Shared Function setCallback_onCallReplaced(cb As delOnCallReplacedCallback) As Integer

  End Function

  Delegate Function delOnDtmfDigitCallback(callId As Integer, digit As Integer) As Integer
  Delegate Function delOnMessageWaitingCallback(mwi As Integer, info As String) As Integer
  Delegate Function delOnCallReplacedCallback(oldid As Integer, newid As Integer) As Integer

  Shared dtdel As delOnDtmfDigitCallback = New delOnDtmfDigitCallback(AddressOf onDtmfDigitCallback)
  Shared mwidel As delOnMessageWaitingCallback = New delOnMessageWaitingCallback(AddressOf onMessageWaitingCallback)
  Shared crepdel As delOnCallReplacedCallback = New delOnCallReplacedCallback(AddressOf onCallReplacedCallback)

#End Region

#Region "Variables"

  '// config structure (used for special configuration options)
  Public ConfigMore As pjsipConfig = pjsipConfig.Instance

#End Region 'Variables

#Region "Private Methods"
  ''' <summary>
  ''' 
  ''' </summary>
  ''' <returns></returns>
  Private Function start() As Integer
    Dim status As Integer = -1

    '// prepare configuration struct
    '// read data from Config interface. If null read all values directly from SipConfigMore
    If Not Config.IsNull Then
      ConfigMore.listenPort = Config.SIPPort
    End If

    dll_setSipConfig(ConfigMore)
    status = dll_init()

    If (status <> 0) Then Return status

    status = status Or dll_main()

    Return status
  End Function
#End Region

#Region "Public Methods"

  ''' <summary>
  ''' Initialize pjsip stack
  ''' </summary>
  ''' <returns></returns>
  Public Overrides Function initialize() As Integer
    '// shutdown if started already
    shutdown()

    '// register callbacks (delegates)
    setCallback_onDtmfDigit(dtdel)
    setCallback_onMessageWaiting(mwidel)
    setCallback_onCallReplaced(crepdel)

    '// init call proxy (callbacks)
    pjsipCallProxy.initialize()

    '// Initialize pjsip...
    Dim status As Integer = start()
    '// set initialized flag
    IsInitialized = If(status = 0, True, False)

    Return status
  End Function

  ''' <summary>
  ''' Shutdown pjsip stack
  ''' </summary>
  ''' <returns></returns>
  Public Overrides Function shutdown() As Integer
    '//if (!IsInitialized) return -1;

    Return dll_shutdown()
  End Function

  ''' <summary>
  ''' Get codec by index
  ''' </summary>
  ''' <param name="index"></param>
  ''' <returns></returns>
  Public Overrides Function getCodec(index As Integer) As String
    If Not IsInitialized Then Return ""

    Dim codec As StringBuilder = New StringBuilder(256)
    dll_getCodec(index, codec)
    Return (codec.ToString())
  End Function

  ''' <summary>
  ''' Get number of all codecs
  ''' </summary>
  ''' <returns></returns>
  Public Overrides Function getNoOfCodecs() As Integer
    If Not IsInitialized Then Return 0

    Dim no As Integer = dll_getNumOfCodecs()
    Return no
  End Function

  ''' <summary>
  ''' Set codec priority
  ''' </summary>
  ''' <param name="codecname"></param>
  ''' <param name="priority"></param>
  Public Overrides Sub setCodecPriority(codecname As String, priority As Integer)
    If Not IsInitialized Then Return
    dll_setCodecPriority(codecname, priority)
  End Sub

  ''' <summary>
  ''' Call proxy factory method
  ''' </summary>
  ''' <returns></returns>
  Public Overrides Function createCallProxy() As ICallProxy
    Return New pjsipCallProxy(Config)
  End Function


  ''' <summary>
  ''' Set sound device for playback and recording
  ''' </summary>
  ''' <param name="playbackDeviceId"></param>
  ''' <param name="recordingDeviceId"></param>
  Public Sub setSoundDevice(playbackDeviceId As String, recordingDeviceId As String)
    Dim status As Integer = dll_setSoundDevice(playbackDeviceId, recordingDeviceId)
  End Sub

#End Region 'Methods

#Region "Callbacks"


  '//////////////////////////////////////////////////////////////////////////////////

  Private Shared Function onDtmfDigitCallback(callId As Integer, digit As Integer) As Integer
    Instance.BaseDtmfDigitReceived(callId, digit)
    Return 1
  End Function

  Private Shared Function onMessageWaitingCallback(mwi As Integer, info As String) As Integer
    If info Is Nothing Then Return -1
    Instance.BaseMessageWaitingIndication(mwi, info.ToString())
    Return 1
  End Function

  Private Shared Function onCallReplacedCallback(oldid As Integer, newid As Integer) As Integer
    Instance.BaseCallReplacedCallback(oldid, newid)
    Return 1
  End Function

#End Region 'Callbacks

#Region "Utility Methods"
  Friend Function SetTransport(accountKey As String, sipuri As String) As String
    Dim temp As String = sipuri

    Try
      '// set transport mode
      Select Case Config.Account(accountKey).TransportMode
        Case ETransportMode.TM_TCP
          temp = sipuri + ";transport=tcp"
        Case ETransportMode.TM_TLS
          temp = sipuri + ";transport=tls"
      End Select
    Catch ex As ArgumentOutOfRangeException
    End Try
    Return temp
  End Function
#End Region

End Class